﻿#include "EditorFolderAbilityViewModel.h"

#include "Asset/EditorDefaultPackage.h"

#include <chrono>
#include <stack>
#include "EditorFolderAbilityModel.h"
#include "Window/EditorWindowGroupModel.h"

#include "Widgets/EditableText/EditorEditableTextViewModel.h"
#include "Widgets/EditorCommonWindow.h"
#include "Widgets/Window.h"
#include "Widgets/EditorTextButton.h"
#include "Widgets/WindowManager.h"
#include "Widgets/TextWidget.h"

#include "File/FileUtils.h"

#include "Pages/EditorPageModel.h"

#include "Asset/ProjectAssetSubsystem.h"

#include "Framework/Editor.h"

#include "Window/EditorWindowGroupViewModel.h"

#include "Platform/PlatformInterface.h"
#include "Output/Console.h"
#include "Project/ProjectModel.h"
#include "Project/ProjectViewModel.h"

void REditorFolderAbilityViewModel::BindModel(TSharedObjectPtr<REditorAbilityModel> InModel)
{
    Super::BindModel(InModel);

    FolderModel = InModel;

    Icon = REditorDefaultPackage::Get()->GetIcon(U"CodiconFiles");
    HighlightIcon = REditorDefaultPackage::Get()->GetIcon(U"CodiconFiles_Highlight");   

    FolderExpendedIcon= REditorDefaultPackage::Get()->GetIcon(U"CodiconChevronDown");
    FolderCollapsedIcon= REditorDefaultPackage::Get()->GetIcon(U"CodiconChevronRight");
    DefaultFileIcon= REditorDefaultPackage::Get()->GetIcon(U"CodiconFiles");

    NewAssetFileIcon= REditorDefaultPackage::Get()->GetIcon(U"NewAssetFile");
    NewFileIcon= REditorDefaultPackage::Get()->GetIcon(U"CodiconNewFile");
    NewFolderIcon= REditorDefaultPackage::Get()->GetIcon(U"CodiconNewFolder");
    RefreshIcon= REditorDefaultPackage::Get()->GetIcon(U"CodiconRefresh");
    CloseAllFoldersIcon= REditorDefaultPackage::Get()->GetIcon(U"CodiconCollapseAll");

    InitializeFileSystem();
    FolderModel->OnRootFolderChanged.Bind([this]()
    {
        InitializeFileSystem();
    });
     FolderModel->OnFolderOpenStateChanged
        .Bind([this](const SPath& Folder, bool bIsOpened)
        {
            auto Node= RootNode;
            while(Node->Path!= Folder)
            {   
                bool bFound= false;
                for(auto& SubFolder: Node->SubFolders)
                {
                    if(Folder.IsInside(SubFolder->Path)
                        || Folder== SubFolder->Path
                    )
                    {
                        Node= SubFolder;
                        bFound= true;
                        break;
                    }
                }

                if(!bFound)
                {
                    //the folder is not in the file system tree
                    return;
                }
            }
            
            Node->bIsOpened= bIsOpened;
            UpdateFileSystem();

        });


    REditorWindowGroupModel::Get()->OnCurrentPageChanged
        .BindScript(this,&REditorFolderAbilityViewModel::OnFrontFileChanged);

    NameEditViewModel= NewObject<REditorEditableTextViewModel>(this);
    NameEditViewModel->SetFontSize(FontSize);
    NameEditViewModel->OnEditingEnded.Add([this](REditorEditableTextViewModel::EReasonForEndEditing InReasonForEndEditing)
    {
        CString Name=NameEditViewModel->GetDisplayText();

        bool bValid=  SPath::IsValidFileOrFolderName(Name).IsEmpty();
        if(bValid)
        {
            if(EditingMode== EEditingMode::CreateFile)
            {
                //检查文件是否已存在
                SPath FilePath= CreatingParentFolder/ NameEditViewModel->GetDisplayText();
                if(FilePath.Exists())
                {
                    WH::PrintLine(U"文件已存在,无法创建");
                }
                else
                {
                    SFileUtils::SaveBinaryTo({}, FilePath);
                }
            }
            else if(EditingMode== EEditingMode::CreateFolder)
            {
                SPath FolderPath= CreatingParentFolder/ NameEditViewModel->GetDisplayText();
                if(FolderPath.Exists())
                {
                    WH::PrintLine(U"文件夹已存在,无法创建");
                }
                else
                {
                    SFileUtils::CreateDirectory(FolderPath);
                }
                
            }  
            else if(EditingMode== EEditingMode::RenameFile
                ||EditingMode== EEditingMode::RenameFolder
            )
            {
                bool bWasAssetFile= RenameFileOrFolderPath.IsAssetFile();
                auto NewFilePath= RenameFileOrFolderPath.Parent()/ NameEditViewModel->GetDisplayText();
                bool bIsAssetFile= NewFilePath.IsAssetFile();

                if(bWasAssetFile!=bIsAssetFile)
                {
                    //TODO: 将资产文件转换为普通文件或者将普通文件转换为资产文件
                    //需要弹出对话框让用户选择
                    WH::PrintLine(U"正在从资产文件转换为普通文件或者从普通文件转换为资产文件，会导致资产系统错误");
                }

                if(bWasAssetFile&&bIsAssetFile)
                {
                    //重命名资产文件
                    RProjectViewModel::Get()->GetSubsystem<RProjectAssetSubsystem>()
                        ->RenameAssetWithDialog(
                            RenameFileOrFolderPath
                            ,NewFilePath);
                }
                else
                {
                    //重命名普通文件/文件夹
                    SFileUtils::RenameFileOrDirectory(RenameFileOrFolderPath, Name);
                }
            }
        }

        EditingMode= EEditingMode::None; //stop creating
        EditingNameNode= nullptr; //stop editing
        NameEditViewModel->SetDisplayText(U""); //clear the text
        
        UpdateFileSystem();
    });

    NameEditViewModel->OnDisplayTextChanged.Add([this]()
    {
        //check if the name is valid
        CString Name= NameEditViewModel->GetDisplayText();

        if(EditingMode==EEditingMode::RenameFile
            ||EditingMode==EEditingMode::RenameFolder
        )
        {
            if(Name==RenameFileOrFolderPath.GetFileOrDirectoryName())
            {
                EditingNameError.Clear();
                return;
            }
        }


        EditingNameError=SPath::IsValidFileOrFolderName(Name);

        if(!EditingNameError.IsEmpty())
        {
            return;
        }
        
        //check if the name is duplicated
        SPath FilePath= CreatingParentFolder/ Name;
        if(FilePath.Exists())
        {
            EditingNameError= U"文件已存在";
            return;
        }

        EditingNameError.Clear();
        


    });

    NameEditViewModel->CanEndEditing.Bind([this](REditorEditableTextViewModel::EReasonForEndEditing InReasonForEndEditing)
    {
        if(InReasonForEndEditing== REditorEditableTextViewModel::EReasonForEndEditing::Confirm)
        {
            if(NameEditViewModel->GetDisplayText().IsEmpty())
            {
                EditingNameError= U"文件名不能为空";
            }

            return EditingNameError.IsEmpty();
        }
        return true;
    });
}

TSharedObjectPtr<RTexture2D> REditorFolderAbilityViewModel::GetIcon() const
{
    return Icon;
}

TSharedObjectPtr<RTexture2D> REditorFolderAbilityViewModel::GetHighlightIcon() const
{
    return HighlightIcon;
}

bool REditorFolderAbilityViewModel::IsValid() const
{
    return FolderModel->GetRootFolder().Exists();
}

int64_t REditorFolderAbilityViewModel::GetVisibleNodeNum() const
{
    return NodeLists.Num()-1;//exclude the root node
}

float REditorFolderAbilityViewModel::GetLineOffset(int64_t Index) const
{
    const float Offset= 5;
    return (NodeLists[Index+1]->Depth-1) *Offset;
}

TSharedObjectPtr<RTexture2D> REditorFolderAbilityViewModel::GetLineIcon(int64_t Index) const
{
    return NodeLists[Index+1]->Icon;
}

CString REditorFolderAbilityViewModel::GetVisibleNodeName(int64_t Index) const
{
    return NodeLists[Index+1]->Path.GetFileOrDirectoryName();
}

void REditorFolderAbilityViewModel::OnNodeClicked(int64_t Index)
{
    if(Index>=0)
    {
        LastLeftMouseClickedNodeIndex= Index+1;
        LastMouseClickedNodeIndex=LastLeftMouseClickedNodeIndex;
    }
    else
    {
        LastLeftMouseClickedNodeIndex= -1;
        LastMouseClickedNodeIndex=LastLeftMouseClickedNodeIndex;
        return;
    }

    switch(NodeLists[Index+1]->Type)
    {
        case ENodeType::Folder:
        if(NodeLists[Index+1]->bIsOpened)
        {
            FolderModel->CloseFolder(NodeLists[Index+1]->Path);
        }
        else
        {
            FolderModel->OpenFolder(NodeLists[Index+1]->Path);
        }
        FocusedPath= NodeLists[Index+1]->Path;
        return ;


        case ENodeType::File:
        REditorWindowGroupModel::Get()->OpenFile(NodeLists[Index+1]->Path);
        FocusedPath= NodeLists[Index+1]->Path;
        return ;

        case ENodeType::CreatingFile:
        case ENodeType::CreatingFolder:
        //do nothing
        return ;

    }

    assert(false && "unreachable");
    return ;
}

void REditorFolderAbilityViewModel::OnNodeRightMouseButtonClicked(int64_t Index)
{
    if(Index>=0)
    {
        LastMouseClickedNodeIndex= Index+1;
    }
    else
    {
        LastMouseClickedNodeIndex= -1;
    }

    //创建并打开右键菜单
    TVector<SEditorContextMenuLine> RootContextMenu;

    if(LastMouseClickedNodeIndex!=-1)
    {
        //鼠标右键点击了一个节点
        switch(NodeLists[LastMouseClickedNodeIndex]->Type)
        {
            case ENodeType::Folder:
                //新建文件
                {
                    auto& CreateFile= RootContextMenu.Emplace();
                    CreateFile.Text=U"新建文件(未实现)";
                }

                //新建文件夹
                {
                    auto& CreateFolder= RootContextMenu.Emplace();
                    CreateFolder.Text=U"新建文件夹(未实现)";
                }

                //在文件资源管理器中打开
                {
                    auto& OpenInExplorer= RootContextMenu.Emplace();
                    OpenInExplorer.Text=U"在文件资源管理器中打开(未实现)";
                }

                //分割线
                {
                    auto& Separator= RootContextMenu.Emplace();
                    Separator.bIsSeparator= true;
                }

                //剪切
                {
                    auto& Cut= RootContextMenu.Emplace();
                    Cut.Text=U"剪切(未实现)";
                }
                //复制
                {
                    auto& Copy= RootContextMenu.Emplace();
                    Copy.Text=U"复制(未实现)";
                }
                //粘贴
                {
                    auto& Paste= RootContextMenu.Emplace();
                    Paste.Text=U"粘贴(未实现)";
                }

                //分割线
                {
                    auto& Separator= RootContextMenu.Emplace();
                    Separator.bIsSeparator= true;
                }

                //重命名
                {
                    auto& Rename= RootContextMenu.Emplace();
                    Rename.Text=U"重命名(未实现)";
                }

                //删除
                {
                    auto& Delete= RootContextMenu.Emplace();
                    Delete.Text=U"删除(未实现)";
                }
                break;
            
            case ENodeType::File:
                //在右侧打开文件
                {
                    auto& OpenAtRight= RootContextMenu.Emplace();
                    OpenAtRight.Text=U"在右侧打开(未实现)";
                }

                //打开方式
                {
                    auto& OpenWith= RootContextMenu.Emplace();
                    OpenWith.Text=U"打开方式(未实现)";
                }

                //在文件资源管理器中打开
                {
                    auto& OpenInExplorer= RootContextMenu.Emplace();
                    OpenInExplorer.Text=U"在文件资源管理器中打开(未实现)";
                }

                
                if(NodeLists[LastMouseClickedNodeIndex]->Path.IsAssetFile())
                {
                    //分割线
                    {
                        auto& Separator= RootContextMenu.Emplace();
                        Separator.bIsSeparator= true;
                    }

                    //复制资产路径
                    {
                        auto& CopyAssetPath= RootContextMenu.Emplace();
                        CopyAssetPath.Text=U"复制资产路径";
                        CopyAssetPath.OnClicked.Bind([this]()
                        {
                            auto AssetPackage=REditor::Get()
                                ->GetSubsystem<RProjectModel>()
                                ->GetAssetPackage().GetValue();
            
                            //读取资产路径
                            auto AssetPath=RAssetSubsystem::Get()
                                ->LoadAssetPath(AssetPackage.Name,NodeLists[LastMouseClickedNodeIndex]->Path);
                            if(!AssetPath.HasValue())
                            {
                                WH::PrintLine(U"无法读取资产路径,可能为空资产");
                                return;
                            }
                           
                            //复制到剪贴板
                            IPlatformInterface::GetPlatformInterface()->SetClipboardText(AssetPath.GetValue().ToString());

                        });
                    }
                }

                //分割线
                {
                    auto& Separator= RootContextMenu.Emplace();
                    Separator.bIsSeparator= true;
                }

                //剪切
                {
                    auto& Cut= RootContextMenu.Emplace();
                    Cut.Text=U"剪切(未实现)";
                }

                //复制
                {
                    auto& Copy= RootContextMenu.Emplace();
                    Copy.Text=U"复制(未实现)";
                }

                //分割线
                {
                    auto& Separator= RootContextMenu.Emplace();
                    Separator.bIsSeparator= true;
                }

                //重命名
                {
                    auto& Rename= RootContextMenu.Emplace();
                    Rename.Text=U"重命名(未实现)";
                }

                //删除
                {
                    auto& Delete= RootContextMenu.Emplace();
                    Delete.Text=U"删除(未实现)";
                }

                break;
            case  ENodeType::CreatingFile:
            case  ENodeType::CreatingFolder:
                
                //撤销
                {
                    auto& Undo= RootContextMenu.Emplace();
                    Undo.Text=U"撤销(未实现)";
                }

                //恢复
                {
                    auto& Redo= RootContextMenu.Emplace();
                    Redo.Text=U"恢复(未实现)";
                }

                //分割线
                {
                    auto& Separator= RootContextMenu.Emplace();
                    Separator.bIsSeparator= true;
                }

                //剪切
                {
                    auto& Cut= RootContextMenu.Emplace();
                    Cut.Text=U"剪切(未实现)";
                }

                //复制
                {
                    auto& Copy= RootContextMenu.Emplace();
                    Copy.Text=U"复制(未实现)";
                }

                //粘贴
                {
                    auto& Paste= RootContextMenu.Emplace();
                    Paste.Text=U"粘贴(未实现)";
                }

                break;
        }

    }
    else
    {
        //鼠标右键点击了空白处

        //新建文件
        {
            auto& CreateFile= RootContextMenu.Emplace();
            CreateFile.Text=U"新建文件(未实现)";
        }

        //新建文件夹
        {
            auto& CreateFolder= RootContextMenu.Emplace();
            CreateFolder.Text=U"新建文件夹(未实现)";
        }

        //在文件资源管理器中打开
        {
            auto& OpenInExplorer= RootContextMenu.Emplace();
            OpenInExplorer.Text=U"在文件资源管理器中打开(未实现)";
        }
    }

    //创建右键菜单
    REditorWindowGroupViewModel::Get()->ShowContextMenu(
        RootContextMenu
        ,SMouseButtonEvent::GetMosuePositionOnScreen()
        ,200
    );
}

int64_t REditorFolderAbilityViewModel::GetFocusedNodeIndex() const
{
    // if(!FocusedPath.IsEmpty() && FocusedPath.Exists())
    // {
    //     for(int64_t i=1;i<NodeLists.Num();i++)
    //     {
    //         if(NodeLists[i]->Path== FocusedPath)
    //         {
    //             return i-1;
    //         }
    //     }
    // }
    

    // return -1;

    if(LastLeftMouseClickedNodeIndex==-1)
    {
        return -1;
    }
    return LastLeftMouseClickedNodeIndex-1;
}

int64_t REditorFolderAbilityViewModel::GetJustClickedFileNodeIndex() const
{
    if(LastMouseClickedNodeIndex==-1)
    {
        return -1;
    }
    return LastMouseClickedNodeIndex-1;
}

int64_t REditorFolderAbilityViewModel::GetEditingFileNodeIndex() const
{
    if(!EditingNameNode)
    {
        return -1;
    }

    return EditingNameNode->VisibleIndex-1;
}

void REditorFolderAbilityViewModel::CreateFile()
{
    if(!FocusedPath.IsEmpty() && FocusedPath.Exists())
    {
        if(FocusedPath.IsDirectory())
        {
            CreatingParentFolder= FocusedPath;
        }
        else
        {
            CreatingParentFolder= FocusedPath.Parent();
        }
    }
    else
    {
        CreatingParentFolder= FolderModel->GetRootFolder();
    }

    //确保父文件夹已经打开
    {
        auto Folder= CreatingParentFolder;
        while(Folder.IsSameWith(FolderModel->GetRootFolder()))
        {
            if(!FolderModel->IsFolderOpened(Folder))
            {
                FolderModel->OpenFolder(Folder);
            }
            Folder= Folder.Parent();
        }
    }

    EditingMode= EEditingMode::CreateFile;

    UpdateFileSystem();

    EditingNameError.Clear();
    NameEditViewModel->StartEditing();
}

void REditorFolderAbilityViewModel::CreateAssetFile()
{
    CreateFile();
    NameEditViewModel->SetDisplayText(U"新资产.asset");
}

void REditorFolderAbilityViewModel::CreateFolder()
{
    if(!FocusedPath.IsEmpty() && FocusedPath.Exists())
    {
        if(FocusedPath.IsDirectory())
        {
            CreatingParentFolder= FocusedPath;
        }
        else
        {
            CreatingParentFolder= FocusedPath.Parent();
        }
    }
    else
    {
        CreatingParentFolder= FolderModel->GetRootFolder();
    }

    //确保父文件夹已经打开
    {
        auto Folder= CreatingParentFolder;
        while(Folder.IsSameWith(FolderModel->GetRootFolder()))
        {
            if(!FolderModel->IsFolderOpened(Folder))
            {
                FolderModel->OpenFolder(Folder);
            }
            Folder= Folder.Parent();
        }
    }

    EditingMode= EEditingMode::CreateFolder;

    UpdateFileSystem();

    EditingNameError.Clear();
    NameEditViewModel->StartEditing();
}

void REditorFolderAbilityViewModel::Refresh()
{
    UpdateFileSystem();
}

void REditorFolderAbilityViewModel::CloseAllFolders()
{
    FolderModel->CloseAllFolders();
}

void REditorFolderAbilityViewModel::RemoveFocusedFileOrFolder()
{
    if(FocusedPath.IsEmpty() || !FocusedPath.Exists())
    {
        return;
    }

    bool bIsFile= FocusedPath.IsFile();

    //create a window to delete the file
    WHE::SCommonWindowCreateInfo WindowInfo;
    WindowInfo.Title=bIsFile? U"删除文件" : U"删除文件夹";
    int64_t WindowHeight= 150;
    WindowInfo.Size=SIntPoint(300,WindowHeight);
    WindowInfo.MinimizeMaximizeButton=false;
    WindowInfo.Resizeable=false;
    WindowInfo.bTitleBlinkEffectForModalWindow=true;

    auto Result=WHE::CreateCommonWindow(WindowInfo);

    auto Window= Result.Window;
    auto WindowContent= Result.WindowContent;
    RWindowWeakPtr WindowWeak= Window;

    auto Message=  NewWidget<RTextWidget>(WindowContent);
    Message->Text=(bIsFile? U"确定要删除文件 " : U"确定要删除文件夹 ")
        + FocusedPath.ToString()+U" 吗？";
    Message->Wrap=ETextWrapMethod::WrapByWidth;
    Message->Anchor.TopReference=WindowContent;
    Message->Anchor.TopOffset=10;
    Message->Anchor.LeftReference=WindowContent;
    Message->Anchor.LeftOffset=10;
    Message->Anchor.RightReference=WindowContent;
    Message->Anchor.RightOffset=10;

    auto CancelButton= WHE::CreateTextButton(U"取消"
        , [WindowWeak]() 
    {
        WindowWeak->Close();
    }
    ,WindowContent);

    CancelButton->Width=80;
    CancelButton->Anchor.RightReference=WindowContent;
    CancelButton->Anchor.RightOffset=10;
    CancelButton->Height=30;
    CancelButton->Y=WindowHeight-70;


    bool bDelete=false;
    auto DeleteButton= WHE::CreateTextButton(U"删除"
        , [WindowWeak,&bDelete]() 
    {
        bDelete=true;
        WindowWeak->Close();
    }
    ,WindowContent);

    DeleteButton->Width=80;
    DeleteButton->Anchor.RightReference=CancelButton;
    DeleteButton->Anchor.RightOffset=10;
    DeleteButton->Anchor.RightReferenceEdge=EHorizontalWidgetEdge::Left;
    DeleteButton->Height=30;
    DeleteButton->Y=WindowHeight-70;


    Window->MoveToScreenCenter();
    //show window
    Window->Show();

    RWindowManager::Get()->MakeWindowModal(Window);

    if(!bDelete)
    {
        return;
    }



    if(FocusedPath.IsFile())
    {
        if(FocusedPath.IsAssetFile())
        {
            RProjectViewModel::Get()->GetSubsystem<RProjectAssetSubsystem>()
                ->DeleteAssetWithDialog(FocusedPath);
        }
        else
        {
            SFileUtils::DeleteFile(FocusedPath);
        }
    }
    else if(FocusedPath.IsDirectory())
    {
        //close the folder first
        if(FolderModel->IsFolderOpened(FocusedPath))
        {
            FolderModel->CloseFolder(FocusedPath);
        }

        //递归删除所有文件
        for(auto& Entry: std::filesystem::recursive_directory_iterator(FocusedPath.GetLowLevel()))
        {
            if(Entry.is_directory())
            {
                //后面再删除
                continue;
            }
            else
            {
                SPath File= Entry.path();
                if(File.IsAssetFile())
                {
                    RProjectViewModel::Get()->GetSubsystem<RProjectAssetSubsystem>()
                        ->DeleteAssetWithDialog(File);
                }
                else
                {
                    SFileUtils::DeleteFile(File);
                }
            }
        }
        
        //删除文件夹
        SFileUtils::DeleteDirectory(FocusedPath);
    }
    else
    {
        assert(false && "unreachable");
    }

    UpdateFileSystem();

}

void REditorFolderAbilityViewModel::RenameFocusedFileOrFolder()
{
    if(FocusedPath.IsEmpty() || !FocusedPath.Exists())
    {
        return;
    }

    if(FocusedPath.IsFile())
    {
        EditingMode= EEditingMode::RenameFile;
        RenameFileOrFolderPath= FocusedPath;
    }
    else
    {
        EditingMode= EEditingMode::RenameFolder;
        RenameFileOrFolderPath= FocusedPath;
    }

    //find the node in visible nodes
    for(int64_t i=1;i<NodeLists.Num();i++)
    {
        if(NodeLists[i]->Path== FocusedPath)
        {
            EditingNameNode= NodeLists[i];
            break;
        }
    }

    assert(EditingNameNode);
    EditingNameNode->bIsRenaming= true;

    EditingNameError.Clear();
    NameEditViewModel->StartEditing();
}


void REditorFolderAbilityViewModel::OnFrontFileChanged(TSharedObjectPtr<REditorPageModel> InFocusedPage)
{
    if(!InFocusedPage)
    {
        return;
    }

    SPath FilePath= InFocusedPage->GetFilePath();
    if(FilePath.IsInside(FolderModel->GetRootFolder()))
    {
        FocusedPath= FilePath;
    }
}

void REditorFolderAbilityViewModel::InitializeFileSystem()
{
    if(FolderModel->GetRootFolder().IsEmpty())
    {
        return;
    }

    //remove opened folders that don't exist anymore
    auto CachedOpenedFolders= FolderModel->GetOpenedFolders();
    for(auto& Folder: FolderModel->GetOpenedFolders())
    {
        if(!Folder.Exists()
            || !Folder.IsDirectory()
        )
        {
            FolderModel->CloseFolder(Folder);
        }
    }
    //FolderModel->OpenFolder(FolderModel->GetRootFolder());

    //initialize the file system tree, only care the opened folders
    RootNode= std::make_shared<SFileSystemNode>();
    RootNode->Path= FolderModel->GetRootFolder();
    RootNode->Type= ENodeType::Folder;
    RootNode->bIsOpened= true;


    std::filesystem::directory_iterator It(RootNode->Path.GetLowLevel());
    std::stack<std::shared_ptr<SFileSystemNode>> Stack;
    Stack.push(RootNode);

    while(!Stack.empty())
    {
        auto CurrentNode= Stack.top();
        Stack.pop();

        for(auto& Entry: std::filesystem::directory_iterator(CurrentNode->Path.GetLowLevel()))
        {
            if(Entry.is_directory())
            {
                auto NewNode= std::make_shared<SFileSystemNode>();
                NewNode->Path= Entry.path();
                NewNode->Type= ENodeType::Folder;
                NewNode->Depth= CurrentNode->Depth+1;
                CurrentNode->SubFolders.Add(NewNode);

                if(FolderModel->IsFolderOpened(NewNode->Path))
                {
                    NewNode->bIsOpened= true;
                    Stack.push(NewNode);
                }
            }
            else
            {
                auto NewNode= std::make_shared<SFileSystemNode>();
                NewNode->Path= Entry.path();
                NewNode->Type= ENodeType::File;
                NewNode->Depth= CurrentNode->Depth+1;
                CurrentNode->SubFiles.Add(NewNode);
            }
        }
    }

    //fill visible nodes
    NodeLists.Clear();
    //preorder traversal
    std::function<void(std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode>)> Traverse;
    Traverse= [&](std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode> Node)
    {
        NodeLists.Add(Node);
        Node->VisibleIndex= NodeLists.Num()-1;
        if(Node->bIsOpened)
        {
            for(auto& SubFolder: Node->SubFolders)
            {
                Traverse(SubFolder);
            }

            for(auto& SubFile: Node->SubFiles)
            {
                NodeLists.Add(SubFile);
                SubFile->VisibleIndex= NodeLists.Num()-1;
            }

        }
    };
    Traverse(RootNode);

    LastUpdateTime= std::filesystem::file_time_type::clock::now();

    OnVisibleListSizeChanged.ExecuteIfBound();

    UpdateIcons();
}

void REditorFolderAbilityViewModel::UpdateFileSystem()
{
    assert(RootNode);

    LastUpdateTime= std::filesystem::file_time_type::clock::now();


    //rebuilt the file system tree
    std::stack<std::shared_ptr<SFileSystemNode>> Stack;
    Stack.push(RootNode);

    RootNode->SubFiles.Clear(false);
    RootNode->SubFolders.Clear(false);
    RootNode->CreatingFileNode= nullptr;
    RootNode->CreatingFolderNode= nullptr;

    while(!Stack.empty())
    {
        auto CurrentNode= Stack.top();
        Stack.pop();

        for(auto& Entry: std::filesystem::directory_iterator(CurrentNode->Path.GetLowLevel()))
        {
            if(Entry.is_directory())
            {
                auto NewNode= std::make_shared<SFileSystemNode>();
                NewNode->Path= Entry.path();
                NewNode->Type= ENodeType::Folder;
                NewNode->Depth= CurrentNode->Depth+1;
                CurrentNode->SubFolders.Add(NewNode);

                if(FolderModel->IsFolderOpened(NewNode->Path))
                {
                    NewNode->bIsOpened= true;
                    Stack.push(NewNode);
                }
            }
            else
            {
                auto NewNode= std::make_shared<SFileSystemNode>();
                NewNode->Path= Entry.path();
                NewNode->Type= ENodeType::File;
                NewNode->Depth= CurrentNode->Depth+1;
                CurrentNode->SubFiles.Add(NewNode);
            }
        }
    
    
        //add creating file node
        if(EditingMode==EEditingMode::CreateFile
            &&CreatingParentFolder== CurrentNode->Path
        )
        {
            auto NewNode= std::make_shared<SFileSystemNode>();
            //NewNode->Path= CurrentNode->Path;
            NewNode->Type= ENodeType::CreatingFile;
            NewNode->Depth= CurrentNode->Depth+1;
            CurrentNode->CreatingFileNode= NewNode;

            EditingNameNode= NewNode;
        }
        else if(EditingMode==EEditingMode::CreateFolder
            &&CreatingParentFolder== CurrentNode->Path
        )
        {
            auto NewNode= std::make_shared<SFileSystemNode>();
            //NewNode->Path= CurrentNode->Path;
            NewNode->Type= ENodeType::CreatingFolder;
            NewNode->Depth= CurrentNode->Depth+1;
            CurrentNode->CreatingFolderNode= NewNode;

            EditingNameNode= NewNode;
        }

    }

    //缓存旧的节点列表
    //保持对缩略图的引用，防止重新加载缩略图
    auto OldList= NodeLists;

    int64_t OldNum= NodeLists.Num();
    NodeLists.Clear(false);

    //fill visible nodes
    //preorder traversal
    std::function<void(std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode>)> Traverse;
    Traverse= [&](std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode> Node)
    {
        NodeLists.Add(Node);
        Node->VisibleIndex= NodeLists.Num()-1;
        if(Node->bIsOpened)
        {
            if(Node->CreatingFolderNode)
            {
                NodeLists.Add(Node->CreatingFolderNode);
                Node->CreatingFolderNode->VisibleIndex= NodeLists.Num()-1;
            }

            for(auto& SubFolder: Node->SubFolders)
            {
                Traverse(SubFolder);
            }

            if(Node->CreatingFileNode)
            {
                NodeLists.Add(Node->CreatingFileNode);
                Node->CreatingFileNode->VisibleIndex= NodeLists.Num()-1;
            }

            for(auto& SubFile: Node->SubFiles)
            {
                NodeLists.Add(SubFile);
                SubFile->VisibleIndex= NodeLists.Num()-1;
            }
        }
    };
    Traverse(RootNode);

    if(OldNum!= NodeLists.Num())
    {
        OnVisibleListSizeChanged.ExecuteIfBound();
    }
    UpdateIcons();
}

void REditorFolderAbilityViewModel::UpdateIcons()
{
    for(auto& Node: NodeLists)
    {
        if(Node->Type== ENodeType::Folder)
        {
            if(Node->bIsOpened)
            {
                Node->Icon= FolderExpendedIcon;
            }
            else
            {
                Node->Icon= FolderCollapsedIcon;
            }
        }
        else if(Node->Type== ENodeType::File)
        {
            Node->Icon= DefaultFileIcon;
            if(Node->Path.IsAssetFile())
            {
                std::weak_ptr<REditorFolderAbilityViewModel::SFileSystemNode> 
                    WeakNode= Node;
                RProjectViewModel::Get()
                ->GetSubsystem<RProjectAssetSubsystem>()
                ->AsyncLoadThumbnail(Node->Path
                ,[WeakNode](TSharedObjectPtr<RTexture2D> InTexture)
                {
                    if(WeakNode.expired())
                    {
                        return;
                    }
                    auto Node= WeakNode.lock();
                    Node->Icon= InTexture;
                }   
                );
            }

        }
        else if(Node->Type== ENodeType::CreatingFile)
        {
            Node->Icon= DefaultFileIcon;
        }
        else if(Node->Type== ENodeType::CreatingFolder)
        {
            Node->Icon= FolderCollapsedIcon;
        }
    }
}

void REditorFolderAbilityViewModel::Tick(float DeltaSeconds)
{
    if(!IsValid())
    {
        return;
    }

    LastDetectTime+= DeltaSeconds;
    const float DetectInterval=1.5f;
    if(LastDetectTime>= DetectInterval)
    {
        LastDetectTime= 0;
        //use last write time to detect file system changes
        auto ModifiedTime= std::filesystem::last_write_time(FolderModel->GetRootFolder().GetLowLevel());
        if(ModifiedTime < LastUpdateTime)
        {
            return;
        }

        UpdateFileSystem();
    }

}
